# 基类
import time

from selenium.common import NoSuchElementException
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support.select import Select
from config.constants import *
import logging


class Base():

    def __init__(self, driver):
        # 双击浏览器
        self.driver = driver  # driver edge firefox chrome
        # 确保screenshots目录存在
        self.screenshot_dir = SCREENSHOT_DIR
        os.makedirs(self.screenshot_dir, exist_ok=True)

    def open_url(self, url):
        self.driver.get(url)

    def maximize_window(self):
        self.driver.maximize_window()

    # 封装时间的方法 ****
    def time(self, name):
        # time.strftime：这是Python的time模块中的一个函数，用于将时间格式化为指定的字符串格式
        # time.localtime()：获取当前本地时间
        t = time.strftime('%Y%m%d%H%M%S', time.localtime())
        screenshot_path = os.path.join(self.screenshot_dir, f"{t}_{name}")
        # save_screenshot：这是Webdriver的一个方法，用于保存当前浏览器窗口的截图
        self.driver.save_screenshot(screenshot_path)
        return screenshot_path  # 返回截图路径，方便后续使用

    def find_element(self, loc, timeout=20, poll_frequency=0.5):
        try:
            element = WebDriverWait(self.driver, timeout, poll_frequency).until(lambda driver: driver.find_element(*loc).is_displayed())
            return self.driver.find_element(*loc)  # *: 不定长参数（解包-解括号）， loc 任意定位元素
        except Exception as e:
            logging.info(f'元素定位不到：{e}')
            # 保存错误截图到screenshots目录
            screenshot_path = self.time('error.png')
            logging.info(f'错误截图已保存到: {screenshot_path}')
            raise  # 重新抛出异常，避免静默失败

    def is_element_visible(self, loc, timeout=20, poll_frequency=0.5):
        """
        判断元素是否可见
        """
        try:
            element = self.find_element(loc, timeout, poll_frequency)
            return element.is_displayed()
        except NoSuchElementException:
            return False

    # 退出浏览器
    def quit(self):
        self.driver.quit()

    def text(self, loc):
        return self.find_element(loc).text

    def send_keys(self, loc, info, clear=True, timeout=20):
        try:
            element = self.find_element(loc, timeout)
            """检查元素是否准备就绪(存在、可见、可交互)"""
            if element if element.is_displayed() and element.is_enabled() else None:
                # 清空并输入内容
                if clear:
                    element.clear()
                element.send_keys(info)
            else:
                logging.info(f'<UNK>交互失败<UNK>')
        except Exception as e:
            error_msg = f"输入操作失败 - 定位器: {loc} - 错误类型: {type(e).__name__} - 错误信息: {str(e)}"
            raise



    def keys_send_enter(self, loc, info):  # 输入内容 键盘回车事件
        self.send_keys(loc, info)
        self.find_element(loc).send_keys(Keys.ENTER)

    def click(self, loc):  # 鼠标点击事件
        self.find_element(loc).click()

    def clear(self, loc):
        self.find_element(loc).clear()

    def base_get_text(self, locator):
        """
        基础方法：获取元素的文本内容
        :param locator: 元素定位器 (By.XPATH, By.ID等)
        :return: 元素的文本内容
        """
        try:
            element = self.find_element(*locator)  # 假设使用Selenium
            return element.text
        except Exception as e:
            logging.info(f"获取文本失败: {str(e)}")
            return None

    # 浏览器事件：
    def back(self):
        self.driver.back()

    def forward(self):
        self.driver.forward()

    def refresh(self):
        self.driver.refresh()

    # 多窗口切换
    def new_window(self):
        self.driver.switch_to.window(self.driver.window_handles[-1])

    # 进入frame框架
    def frame(self, loc):
        self.driver.switch_to.frame(self.find_element(loc))

    def frame_tc(self):
        """退出frame框架"""
        self.driver.switch_to.default_content()

    # Select下拉框的封装 *********
    def select_by_value(self, loc, value):
        """通过value选择下拉菜单选项"""
        select = Select(self.find_element(loc))
        select.select_by_value(value)

    def select_by_visible_text(self, loc, text):
        """通过可见文本选择下拉菜单选项"""
        select = Select(self.find_element(loc))
        select.select_by_visible_text(text)

    def select_by_index(self, loc, index):
        """通过索引选择下拉菜单选项"""
        select = Select(self.find_element(loc))
        select.select_by_index(index)

    # 弹窗的封装 *********
    def accept_alert(self):
        """接受弹窗"""
        alert = self.driver.switch_to.alert
        alert.accept()

    def dismiss_alert(self):
        """取消弹窗"""
        alert = self.driver.switch_to.alert
        alert.dismiss()

    def get_alert_text(self):
        """获取弹窗文本"""
        alert = self.driver.switch_to.alert
        return alert.text

    def send_text_to_alert(self, text):
        """在弹窗中输入文本并接受弹窗"""
        alert = self.driver.switch_to.alert
        alert.send_keys(text)
        alert.accept()

    # 滚动条的封装 *************
    def scroll_to_element(self, loc):
        """滚动到指定元素"""
        element = self.find_element(loc)
        self.driver.execute_script("arguments[0].scrollIntoView();", element)

    def scroll_to_px(self, px):
        """滚动指定像素"""
        self.driver.execute_script(f"window.scrollTo(0, {px});")

    def scroll_to_top(self):
        """滚动到页面顶部"""
        self.driver.execute_script("window.scrollTo(0, 0);")

    def scroll_to_bottom(self):
        """滚动到页面底部"""
        self.driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")

    # 键盘事件的封装 **********
    def keys_enter(self):
        """键盘回车事件"""
        self.send_keys(Keys.ENTER)

    def keys_control_a(self, loc):
        """键盘全选事件"""
        self.find_element(loc).send_keys(Keys.CONTROL, 'a')

    def keys_control_c(self, loc):
        """键盘复制事件"""
        self.find_element(loc).send_keys(Keys.CONTROL, 'c')

    def keys_control_v(self, loc):
        """键盘粘贴事件"""
        self.find_element(loc).send_keys(Keys.CONTROL, 'v')

    def keys_control_x(self, loc):
        """键盘剪切事件"""
        self.find_element(loc).send_keys(Keys.CONTROL, 'x')

    def keys_delete(self, loc):
        """键盘删除事件"""
        self.find_element(loc).send_keys(Keys.DELETE)

    def keys_backspace(self, loc):
        """键盘退格事件"""
        self.find_element(loc).send_keys(Keys.BACKSPACE)

    # 鼠标事件的封装 **********
    def move_to_element(self, loc):
        """鼠标悬停事件"""
        ActionChains(self.driver).move_to_element(self.find_element(loc)).perform()

    def context_click(self, loc):
        """鼠标右击事件"""
        ActionChains(self.driver).context_click(self.find_element(loc)).perform()

    def double_click(self, loc):
        """鼠标双击事件"""
        ActionChains(self.driver).double_click(self.find_element(loc)).perform()

    def double_click_click(self, loc):
        """鼠标三击事件"""
        ActionChains(self.driver).double_click(self.find_element(loc)).click(self.find_element(loc)).perform()

    def click_and_hold(self, loc):
        """鼠标长按事件"""
        ActionChains(self.driver).click_and_hold(self.find_element(loc)).perform()

    def release(self, loc):
        """鼠标释放事件"""
        ActionChains(self.driver).release(self.find_element(loc)).perform()

    def move_by_offset(self, x_px, y_px):
        """鼠标移动事件（按照像素移动）"""
        ActionChains(self.driver).move_by_offset(x_px, y_px).perform()





